﻿using SUNRPA.BROWSER.BRIDGE.domain;
using System;
using System.IO;
using System.IO.Pipes;
using System.Text;
using System.Threading;
using System.Threading.Tasks;

namespace SUNRPA.BROWSER.BRIDGE.util {
    public class NamedPipeServerUtil {
        public static LogUtil logger = new LogUtil(typeof(NamedPipeServerUtil));
        private static NamedPipeServerStream server;
        private static CancellationTokenSource workerSwitch = new CancellationTokenSource();
        public static void Dispose() {
            if (server != null) { 
                server.Dispose();
            }
        }

        public static void CancelServerWorker() { 
            workerSwitch.Cancel();
        }

        public static void Init(string serverName, PipeDirection pipeDirection) { 
            server = new NamedPipeServerStream(serverName, pipeDirection, 1, PipeTransmissionMode.Message);
            server.ReadMode = PipeTransmissionMode.Message;
        }

        public static NamePipeRequest ReadRequest(){
            using(MemoryStream ms = new MemoryStream()){
                byte[] buffer = new byte[0x1000];
                do {
                    ms.Write(buffer, 0, server.Read(buffer, 0, buffer.Length));
                } while(!server.IsMessageComplete);
                return DataUtil.DeSerializeJson<NamePipeRequest>(Encoding.UTF8.GetString(ms.ToArray()), false);
            } 
        }

        public static void WritResponse(BridgeResponse msg) {
            byte[] resp = Encoding.UTF8.GetBytes(DataUtil.ObjectJsonSerializer(msg, true));
            server.Write(resp, 0, resp.Length);
            server.Flush();
        }

        public static Task BeginNamedPipWorker() { 
            Task task = Task.Run(() => {
                while(!workerSwitch.Token.IsCancellationRequested) { 
                    try{
                        server.WaitForConnection();
                        //读请求
                        NamePipeRequest req = ReadRequest();
                        //处理数据
                        //请求后相应直接返回给主程序，主程序知道响应该如何处理
                        BridgeResponse bridgeResponse = BrowserCommUtil.WriteMsgToBrowser(BrowserRequestWrapper.GetBrowserRequest(req));
                        if("close".Equals(bridgeResponse.msg)) {
                            bridgeResponse.msg = "浏览器插件已关闭，请检查";
                            bridgeResponse.code = CommunicationCode.ERROR;
                            logger.Info("浏览器插件已关闭，关闭中间程序");
                            CancelServerWorker();
                            BrowserCommUtil.CloseBrowserCommWorker();
                        }
                        //写响应,直接将相应返回给客户端，对应请求客户端知道该如何处理响应
                        WritResponse(bridgeResponse);
                        server.Disconnect();
                    } catch(Exception e){
                        logger.Error("进程通信监听线程出错，请检查", e);
                        server.Disconnect();
                        //CancelServerWorker();
                    }
                }
                logger.Info("进程通信服务端监听线程结束");
            });
            return task;
        }
    }
}
